<template>
    <div :id="id"></div>
</template>

<script>
import Chart from '../../chart.js'
import * as d3 from 'd3'
import { defineComponent } from 'vue'

export default defineComponent({
    props: {
        id: {
            required: true,
        },
        data: {
            required: true,
        },
        width: {},
        height: {},
        modelValue: {},
    },
    emit: ['update:modelValue'],
    data() {
        return {}
    },
    mounted() {},
    watch: {
        data: {
            handler(value) {
                this.initMap(value)
            },
            deep: true,
        },
    },
    computed: {
        dataLength() {
            return Object.keys(this.data).length
        },
    },
    methods: {
        initMap(data) {
            const me = this
            const chart = new Chart()
            const box = d3.select('#' + this.id)
            box.node().innerHTML = ''
            box.node().style.width = this.width + 'px'
            box.node().style.height = this.height + 'px'

            const config = {
                barPadding: 0.4,
                barColor: '#296FFF7F',
                margins: { top: 16, left: 60, bottom: 46, right: 15 },
                textColor: '#ffffff',
                gridColor: 'gray',
                tickShowGrid: [60, 120, 180],
                title: '',
                hoverColor: '#296FFF',
                animateDuration: 1000,
            }

            chart.box(box)
            chart.margins(config.margins)
            chart.setId(this.id)
            chart.width(this.width)
            chart.height(this.height)

            /* ----------------------------尺度转换------------------------  */
            chart.scaleX = d3
                .scaleBand()
                .domain(data.map(d => d.date))
                .range([0, chart.getBodyWidth()])
                .padding(config.barPadding)

            chart.scaleY = d3
                .scaleLinear()
                // .domain([0, d3.max(data, (d) => d.value) * 1.2])
                .domain([0, Math.max(d3.max(data, d => d.value) * 1.2, 10)])
                .range([chart.getBodyHeight(), 0])
                .nice()

            /* ----------------------------渲染柱形------------------------  */
            chart.renderBars = function () {
                const bars = chart.body().selectAll(`.${me.id}-bar`).data(data)

                bars.enter()
                    .append('rect')
                    .attr('class', `${me.id}-bar`)
                    .classed('pointer', true)
                    .merge(bars)
                    .attr('x', d => chart.scaleX(d.date))
                    .attr('y', chart.scaleY(0))
                    .attr('width', chart.scaleX.bandwidth())
                    .attr('height', 0)
                    .attr('fill', config.barColor)
                    .transition()
                    .duration(config.animateDuration)
                    .attr('height', d => chart.getBodyHeight() - chart.scaleY(d.value))
                    .attr('y', d => chart.scaleY(d.value))

                bars.exit().remove()
            }

            /* ----------------------------渲染坐标轴------------------------  */
            chart.renderX = function () {
                const xTick = d3
                    .axisBottom(chart.scaleX)
                    .tickSize(0)
                    .tickPadding(15.5)
                    .tickFormat(d => {
                        return d
                    })
                const xAxis = chart
                    .svg()
                    .insert('g', '.body')
                    .attr(
                        'transform',
                        'translate(' + chart.bodyX() + ',' + (chart.bodyY() + chart.getBodyHeight()) + ')',
                    )
                    .attr('class', 'xAxis')
                    .call(xTick)

                xAxis.select('path').remove()
                xAxis.selectAll('text').attr('opacity', 0.5).attr('style', 'font-size:8px')
            }

            chart.renderY = function () {
                const yTick = d3.axisLeft(chart.scaleY).tickSize(0).tickPadding(14)
                const yAxis = chart
                    .svg()
                    .insert('g', '.body')
                    .attr('transform', 'translate(' + chart.bodyX() + ',' + chart.bodyY() + ')')
                    .attr('class', 'yAxis')
                    .call(yTick)

                yAxis.select('path').remove()
                yAxis.selectAll('text').attr('opacity', 0.5).attr('style', 'font-size:8px')
            }

            chart.renderAxis = function () {
                chart.renderX()
                chart.renderY()
            }

            /* ----------------------------渲染文本标签------------------------  */
            chart.renderText = function () {
                d3.select('.xAxis')
                    .append('text')
                    .attr('class', 'axisText')
                    .attr('x', chart.getBodyWidth())
                    .attr('y', 0)
                    .attr('fill', config.textColor)
                    .attr('dy', 30)
                    .text('日期')

                d3.select('.yAxis')
                    .append('text')
                    .attr('class', 'axisText')
                    .attr('x', 0)
                    .attr('y', 0)
                    .attr('fill', config.textColor)
                    .attr('transform', 'rotate(-90)')
                    .attr('dy', -40)
                    .attr('text-anchor', 'end')
                    .text('每日收入（元）')
            }

            /* ----------------------------渲染网格线------------------------  */
            chart.renderGrid = function () {
                d3.selectAll('.yAxis .tick').each(function (d) {
                    if (config.tickShowGrid.indexOf(d) > -1) {
                        d3.select(this)
                            .append('line')
                            .attr('class', 'grid')
                            .attr('stroke', '#ecf4ff')
                            .attr('stroke-width', '1px')
                            .attr('x1', 0)
                            .attr('y1', 0)
                            .attr('x2', chart.getBodyWidth())
                            .attr('y2', 0)
                    }
                })
            }

            /* ----------------------------渲染图标题------------------------  */
            chart.renderTitle = function () {
                chart
                    .svg()
                    .append('text')
                    .classed('title', true)
                    .attr('x', chart.width() / 2)
                    .attr('y', 0)
                    .attr('dy', '2em')
                    .text(config.title)
                    .attr('fill', config.textColor)
                    .attr('text-anchor', 'middle')
                    .attr('stroke', config.textColor)
            }

            /* ----------------------------绑定鼠标交互事件------------------------  */
            chart.addMouseOn = function () {
                d3.selectAll(`.${me.id}-bar`)
                    .on('mouseover', function (d, i) {
                        const e = d3.event
                        const position = d3.mouse(chart.svg().node())
                        d3.select(e.target)
                            .transition()
                            .duration(config.animateDuration / 2)
                            .attr('fill', config.hoverColor)

                        chart
                            .svg()
                            .append('text')
                            .classed('tip', true)
                            .attr('x', () => {
                                let x = position[0] + 15
                                if (i > me.dataLength / 2) {
                                    x = position[0] - 15
                                }
                                return x
                            })
                            .attr('y', position[1] - 10)
                            .transition()
                            .duration(config.animateDuration / 2)
                            .attr('fill', config.textColor)
                            .text(d.date + ' 实时风险:' + d.value)
                            .attr('text-anchor', () => {
                                let textAnchor = 'start'
                                if (i > me.dataLength / 2) {
                                    textAnchor = 'end'
                                }
                                return textAnchor
                            })
                    })
                    .on('mouseleave', function () {
                        const e = d3.event

                        d3.select(e.target)
                            .transition()
                            .duration(config.animateDuration / 2)
                            .attr('fill', config.barColor)

                        d3.select('.tip').remove()
                    })
                    .on('mousemove', function (d, i) {
                        const position = d3.mouse(chart.svg().node())
                        d3.select('.tip')
                            .attr('x', () => {
                                let x = position[0] + 15
                                if (i > me.dataLength / 2) {
                                    x = position[0] - 15
                                }
                                return x
                            })
                            .attr('y', position[1] - 10)
                    })
                    .on('click', function (d, i) {
                        me.$emit('update:modelValue', i)
                    })
            }

            chart.render = function () {
                chart.renderAxis()

                // chart.renderText()

                // chart.renderGrid()

                chart.renderBars()

                chart.addMouseOn()

                chart.renderTitle()
            }

            chart.renderChart()
        },
    },
})
</script>

<style lang="scss" scoped></style>
